<?php
/**
 * Created by PhpStorm.
 * User: wiggin
 * Date: 2017/11/18
 */

namespace App\Utility\Curl;

class Curl
{
    private $_ch;

    public $options;
    public $postMultiPart = false;

    private $_config = array(
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_FOLLOWLOCATION => true,
        CURLOPT_AUTOREFERER => true,
        CURLOPT_CONNECTTIMEOUT => 10,
        CURLOPT_TIMEOUT => 60,
        CURLOPT_SSL_VERIFYPEER => false,
        //CURLOPT_PROXY => '127.0.0.1:8888', //增加代理调试功能(便于抓包)
        CURLOPT_USERAGENT => 'Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:5.0) Gecko/20110619 Firefox/5.0'
    );

    // initialize curl
    public function init()
    {
        try {
            $this->_ch = curl_init();
            $options = is_array($this->options) ? ($this->options + $this->_config) : $this->_config;
            $this->setOptions($options);
        } catch (\Exception $e) {
            throw new \Exception('Curl not installed' . $e->getMessage());
        }
    }

    public function get($url, $params = array())
    {
        $this->setOption(CURLOPT_HTTPGET, true);
        return $this->_exec($this->buildUrl($url, $params));
    }

    public function post($url, $data = array())
    {
        if (is_array($data) && count($data) && !$this->postMultiPart) {
            $data = http_build_query($data);
        }
        $this->setOption(CURLOPT_POST, true);
        $this->setOption(CURLOPT_POSTFIELDS, $data);
        return $this->_exec($url);
    }

    public function put($url, $data, $params = array())
    {
        $f = fopen('php://temp', 'rw+');
        fwrite($f, $data);
        rewind($f);
        $this->setOption(CURLOPT_PUT, true);
        $this->setOption(CURLOPT_INFILE, $f);
        $this->setOption(CURLOPT_INFILESIZE, strlen($data));

        return $this->_exec($this->buildUrl($url, $params));
    }

    public function delete($url, $params = array())
    {
        $this->setOption(CURLOPT_RETURNTRANSFER, true);
        $this->setOption(CURLOPT_CUSTOMREQUEST, 'DELETE');
        return $this->_exec($this->buildUrl($url, $params));
    }

    public function buildUrl($url, $data = array())
    {
        $parsed = parse_url($url);
        isset($parsed['query']) ? parse_str($parsed['query'], $parsed['query']) : $parsed['query'] = array();
        $params = isset($parsed['query']) ? array_merge($parsed['query'], $data) : $data;
        $parsed['query'] = ($params) ? '?' . http_build_query($params) : '';
        if (!isset($parsed['path'])) {
            $parsed['path'] = '/';
        }
        $host = isset($parsed['port']) ? $parsed['host'] . ':' . $parsed['port'] : $parsed['host'];
        return $parsed['scheme'] . '://' . $host . $parsed['path'] . $parsed['query'];
    }

    public function setOptions($options = array())
    {
        curl_setopt_array($this->_ch, $options);
        return $this;
    }

    public function setOption($option, $value)
    {
        curl_setopt($this->_ch, $option, $value);
        return $this;
    }

    public function setHeaders($header = array())
    {
        if ($this->_isAssoc($header)) {
            $out = array();
            foreach ($header as $k => $v) {
                $out[] = $k . ': ' . $v;
            }
            $header = $out;
        }
        $this->setOption(CURLOPT_HTTPHEADER, $header);
        return $this;
    }

    private function _exec($url)
    {
        $return = array(
            'status' => false,
            'errorMsg' => '',
            'data' => ''
        );
        $this->setOption(CURLOPT_URL, $url);
        try {
            $c = curl_exec($this->_ch);
            $this->setOption(CURLOPT_HTTPHEADER, array());  //清空上次请求的头部信息
            if (!curl_errno($this->_ch)) {
                $return['status'] = true;
                $return['data'] = $c;
            } else {
                throw new \Exception(curl_error($this->_ch) . ';URL->' . $url);
            }
        } catch (\Exception $e) {
            $return['errorMsg'] = 'Exception:' . $e->getMessage();
        }
        if ($this->_ch && is_resource($this->_ch)) {
            curl_close($this->_ch);
        }
        return $return;
    }

    private function _isAssoc($arr)
    {
        return array_keys($arr) !== range(0, count($arr) - 1);
    }

    public function getInfo()
    {
        return curl_getinfo($this->_ch);
    }
}